package com.zhu.rtda.heap;

import com.zhu.classfile.ClassBinary;
import com.zhu.classpath.ClassPathManager;
import com.zhu.rtda.Slot;
import com.zhu.rtda.heap.constant.*;
import com.zhu.utils.ClassDataUtil;
import java.io.InputStream;
import java.util.Map;

//类加载器
public class ClassLoader {
    private ClassPathManager classPathManager;

    public ClassLoader(ClassPathManager classPathManager){

        this.classPathManager=classPathManager;

    }

    public InstanceKlass loadClass(String className){
        //访问方法区
        Map<String, InstanceKlass> classMap = MethodArea.getInstance().getClassMap();
        if (classMap.containsKey(className)){
            return classMap.get(className);
        }
        InstanceKlass instanceKlass = loadNonArrayClass(className);
        classMap.put(instanceKlass.getName(),instanceKlass);
        //这里别忘了还要考虑加载当前类的父类和接口（递归）
        return instanceKlass;
    }

    private InstanceKlass loadNonArrayClass(String className){
        byte[] bytes = readClass(className);
        ClassBinary classBinary = ClassBinary.parseClassDataToClassBinary(bytes);
        InstanceKlass instanceKlass = InstanceKlass.fromClassBinaryToInstanceKlass(classBinary);
        instanceKlass.setClassLoader(this);
        resolveSuperClass(instanceKlass);
        resolveInterfaces(instanceKlass);
        link(instanceKlass);
        return instanceKlass;
    }
    //解析当前类的父类
    private static void resolveSuperClass(InstanceKlass klass){
        if (!klass.getSuperClassName().equals("java/lang/Object")){
            InstanceKlass superClass = klass.getClassLoader().loadClass(klass.getSuperClassName());
            klass.setSuperClass(superClass);
        }
    }
    //加载每个类的接口
    private static void resolveInterfaces(InstanceKlass klass){
        int interfaceCount = klass.getInterfaces().length;
        if (interfaceCount>0){
            klass.setInterfaces(new InstanceKlass[interfaceCount]);
            for (int i=0;i<interfaceCount;i++) {
                 klass.getInterfaces()[i]=klass.getClassLoader().loadClass(klass.getInterfaceNames()[i]);
            }
        }
    }
    private byte[] readClass(String className)  {
        try {
            InputStream is = classPathManager.readClass(className);
            return ClassDataUtil.readAllBytes(is);
        }catch (Exception e){
            throw new RuntimeException("classData I/O error occurs");
        }
    }

    /**
     * 链接阶段：验证 + 准备
     */
    private void link(InstanceKlass klass) {
        verify(klass);
        prepare(klass);
    }

    /**
     * 验证阶段（暂未实现）
     */
    private void verify(InstanceKlass klass) {
        // TODO: 后续可加入字节码验证逻辑
    }

    /**
     * 准备阶段：为类分配内存（计算槽位、分配静态变量空间、初始化 final 静态常量）
     */
    private void prepare(InstanceKlass klass) {
        calcInstanceFieldSlotIds(klass);
        calcStaticFieldSlotIds(klass);
        allocAndInitStaticVars(klass);
    }

    /**
     * 计算实例字段的槽位 ID（包括从父类继承的字段）
     * 槽位从 0 开始连续分配，long/double 占两个槽。
     */
    private void calcInstanceFieldSlotIds(InstanceKlass klass) {
        int slotId = 0;
        // 继承父类的实例槽位数
        if (klass.getSuperClass() != null) {
            slotId = klass.getSuperClass().getInstanceSlotCount();
        }
        // 为当前类的非静态字段分配槽位
        for (Field field : klass.getFields()) {
            if (!field.isStatic()) {
                field.setSlotId(slotId);
                slotId++;
                if (field.isLongOrDouble()) {
                    // long 和 double 占两个槽
                    slotId++;
                }
            }
        }
        klass.setInstanceSlotCount(slotId);
    }

    /**
     * 计算静态字段的槽位 ID
     * 静态字段不继承，只计算本类定义的。
     */
    private void calcStaticFieldSlotIds(InstanceKlass klass) {
        int slotId = 0;
        for (Field field : klass.getFields()) {
            if (field.isStatic()) {
                field.setSlotId(slotId);
                slotId++;
                if (field.isLongOrDouble()) {
                    slotId++; // long 和 double 占两个槽
                }
            }
        }
        klass.setStaticSlotCount(slotId);
    }

    /**
     * 分配静态变量空间，并初始化 static final 常量
     */
    private void allocAndInitStaticVars(InstanceKlass klass) {
        int staticSlotCount = klass.getStaticSlotCount();
        Slot[] staticVars = new Slot[staticSlotCount];
        // 初始化所有槽为默认值（num=0, ref=null）
        for (int i = 0; i < staticSlotCount; i++) {
            staticVars[i] = new Slot();
        }
        klass.setStaticVars(staticVars);
        // 初始化 static final 常量
        for (Field field : klass.getFields()) {
            if (field.isStatic() && field.isFinal()) {
                initStaticFinalVar(klass, field);
            }
        }
    }

    /**
     * 初始化 static final 字段（基本类型或 String）
     * 从常量池中读取 ConstValue 属性对应的值，并写入静态变量槽。
     */
    /**
     * 初始化 static final 字段（仅限基本类型和 String）
     * 值来自常量池中的 ConstantValue 属性。
     *
     * 注意：
     * - long/double 占用两个连续 slot
     * - float 使用 Float.floatToRawIntBits() 转为 int 存入 num
     * - String 等引用类型暂不支持（需额外处理），此处抛异常或跳过
     */
    private void initStaticFinalVar(InstanceKlass klass,Field field) {
        // 获取字段关联的运行时常量池
        RuntimeConstantPool cp = klass.getConstantPool();
        // 获取 ConstantValue 属性指向的常量池索引（若无则为 0）
        int cpIndex = field.getConstValueIndex();
        if (cpIndex <= 0) {
            // 该字段没有 ConstantValue 属性（例如非编译时常量），跳过初始化
            return;
        }
        // 获取静态变量槽区（已在 allocAndInitStaticVars 中分配）
        Slot[] staticVars = klass.getStaticVars();
        // 获取该字段在静态槽区中的起始位置
        int slotId = field.getSlotId();
        // 从运行时常量池中获取常量对象（类型为 Constant 的某个子类）
        Constant constant = cp.getConstant(cpIndex);
        // 根据字段描述符（descriptor）分发处理不同类型的常量
        String descriptor = field.getDescriptor();
        switch (descriptor) {
            case "Z": // boolean: true=1, false=0
            case "B": // byte
            case "C": // char
            case "S": // short
            case "I": // int
                if (!(constant instanceof IntegerConstant)) {
                    throw new RuntimeException(
                            "Field '" + field.getName() + "' expects an IntegerConstant in constant pool, " +
                                    "but found: " + constant.getClass().getSimpleName());
                }
                int intValue = ((IntegerConstant) constant).getValue();
                staticVars[slotId].setNum(intValue);
                break;
            case "F": // float
                if (!(constant instanceof FloatConstant)) {
                    throw new RuntimeException(
                            "Field '" + field.getName() + "' expects a FloatConstant in constant pool, " +
                                    "but found: " + constant.getClass().getSimpleName());
                }
                float floatValue = ((FloatConstant) constant).getValue();
                // 将 float 值按 IEEE 754 标准转换为原始 int 位模式（不触发 NaN 规范化）
                int floatBits = Float.floatToRawIntBits(floatValue);
                staticVars[slotId].setNum(floatBits);
                break;
            case "J": // long
                if (!(constant instanceof LongConstant)) {
                    throw new RuntimeException(
                            "Field '" + field.getName() + "' expects a LongConstant in constant pool, " +
                                    "but found: " + constant.getClass().getSimpleName());
                }
                long longValue = ((LongConstant) constant).getValue();
                // 拆分为两个 32 位部分：低位在前，高位在后（小端序风格，与 JVM 规范一致）
                staticVars[slotId].setNum((int) (longValue));         // low 32 bits
                staticVars[slotId + 1].setNum((int) (longValue >> 32)); // high 32 bits
                break;
            case "D": // double
                if (!(constant instanceof DoubleConstant)) {
                    throw new RuntimeException(
                            "Field '" + field.getName() + "' expects a DoubleConstant in constant pool, " +
                                    "but found: " + constant.getClass().getSimpleName());
                }
                double doubleValue = ((DoubleConstant) constant).getValue();
                // 将 double 值转换为原始 64 位 long 表示
                long doubleBits = Double.doubleToRawLongBits(doubleValue);
                // 拆分为两个 32 位部分，存入两个连续 Slot
                staticVars[slotId].setNum((int) (doubleBits));         // low
                staticVars[slotId + 1].setNum((int) (doubleBits >> 32)); // high
                break;
            // region String and other reference types: not supported in prepare phase
            case "Ljava/lang/String;":
                // 注意：虽然 Java 语法允许 "static final String s = \"hello\";",
                // 但 JVMS 并不要求在 prepare 阶段创建字符串对象。
                // 实际上，字符串字面量的解析通常由 ldc 指令触发，并通过字符串常量池管理。
                // 此处抛出异常以明确表示暂不支持，避免静默失败。
                throw new RuntimeException(
                        "String static final field '" + field.getName() +
                                "' is not initialized during preparation phase. " +
                                "This is by design per JVMS specification.");
            default:
                throw new RuntimeException(
                        "Unsupported static final field type descriptor: " + descriptor +
                                " for field '" + field.getName() + "'");
        }
    }
}
